#include "CEffect.h"
#include "CEffectProp.h"
#include "CTextureAnimation.h"
#include "CParticleSystem.h"
#include "WareMacro.h"
#include "IEffectUnitProp.h"
#include "ISceneNodeTransform.h"

BEGIN_WARE

CEffect::CEffect(uint32 uID)
: m_pEffectProp(NULL)
, m_uID(uID)
, m_pParent(NULL)
, m_uStartTime(0)
, m_bVisible(VTRUE)
, m_bWireFrameMode(VFALSE)
{
}

CEffect::~CEffect(void)
{
	if( m_pEffectProp )
		m_pEffectProp->Drop();
	
	size_t size = m_vecEffectUnitTrack.size();
	for( size_t i = 0; i < size; ++i )
	{
		if( m_vecEffectUnitTrack[i] )
			ReleaseEffectUnit( m_vecEffectUnitTrack[i]->pEffectUnit );
		SAFE_DELETE( m_vecEffectUnitTrack[i] );
	}

}

int32 CEffect::Drop()
{
	delete this;
	return 0;
}

void CEffect::CullVisibleObjects( IGraphic* pGraphic, ISceneNodeCamera* pCamera )
{
	size_t size = m_vecEffectUnitTrack.size();
	for( size_t i = 0; i < size; ++i )
	{
		if( m_vecEffectUnitTrack[i]->bActive && m_vecEffectUnitTrack[i]->pEffectUnit )
			m_vecEffectUnitTrack[i]->pEffectUnit->CullVisibleObjects( pGraphic, pCamera );
	}	
}

VBOOL CEffect::Update( IGraphic* pGraphic, uint32 uCurTime )
{
	CEffectProp* pProp = static_cast<CEffectProp*>( m_pEffectProp );
	if( !pProp )
		return VFALSE;

	if( m_uStartTime == 0 )
		m_uStartTime = uCurTime;

	float32 fElapseTime = static_cast<float32>( uCurTime - m_uStartTime );
	float32 fTotalTime = static_cast<float32>( pProp->m_uTotalTime );
	float32 fPos = fElapseTime / fTotalTime;
	fPos = WareMath::Tail( fPos );

	CMatrix4 mat;
	ISceneNodeTransform* pNode = GetParent();
	if( pNode )
		pNode->GetWorldTransform().GetMatrix4( mat );

	CEffectUnit* pEffectUnit = NULL;
	size_t size = m_vecEffectUnitTrack.size();
	for( size_t i = 0; i < size; ++i )
	{
		if( m_vecEffectUnitTrack[i]->pEffectUnit )
		{
			pEffectUnit = static_cast<CEffectUnit*>( m_vecEffectUnitTrack[i]->pEffectUnit );

			if( fPos >= m_vecEffectUnitTrack[i]->fStartPos && fPos <= m_vecEffectUnitTrack[i]->fEndPos )
			{
				if( !m_vecEffectUnitTrack[i]->bActive )
					pEffectUnit->SetStartTime( uCurTime );

				m_vecEffectUnitTrack[i]->bActive = VTRUE;

				pEffectUnit = static_cast<CEffectUnit*>( m_vecEffectUnitTrack[i]->pEffectUnit );
				pEffectUnit->Update( pGraphic, mat, uCurTime );
			}
			else
			{
				pEffectUnit->SetStartTime( 0 );
				m_vecEffectUnitTrack[i]->bActive = VFALSE;
			}
		}
	}

	return VTRUE;
}

VBOOL CEffect::Render( IGraphic* pGraphic, uint32 uCurTime )
{
	CEffectProp* pProp = static_cast<CEffectProp*>( m_pEffectProp );
	if( !pProp )
		return VFALSE;

	float32 fElapseTime = static_cast<float32>( uCurTime - m_uStartTime );
	float32 fTotalTime = static_cast<float32>( pProp->m_uTotalTime );
	float32 fPos = fElapseTime / fTotalTime;
	fPos = WareMath::Tail( fPos );

	CEffectUnit* pEffectUnit = NULL;
	size_t size = m_vecEffectUnitTrack.size();
	for( size_t i = 0; i < size; ++i )
	{
		if( m_vecEffectUnitTrack[i]->pEffectUnit )
		{
			pEffectUnit = static_cast<CEffectUnit*>( m_vecEffectUnitTrack[i]->pEffectUnit );

			if( fPos >= m_vecEffectUnitTrack[i]->fStartPos && fPos <= m_vecEffectUnitTrack[i]->fEndPos )
			{
				pEffectUnit->Render( pGraphic, uCurTime );
			}
		}
	}

	return VTRUE;
}

IEffectProp* CEffect::GetEffectProp()
{
	return m_pEffectProp;
}

//////////////////////////////////////////////////////////////////////////
VBOOL CEffect::CreateEffect( IResourceManager* pResMgr, IEffectProp* pEffectProp )
{
	if( !pEffectProp )
		return VFALSE;

	if( m_pEffectProp )
		m_pEffectProp->Drop();

	m_pEffectProp = pEffectProp;
	pEffectProp->Grab();

	///
	CEffectProp* pProp = static_cast<CEffectProp*>( pEffectProp );
	const EffectUnitTrack& Track = pProp->GetEffectUnitTracks();

	size_t size = Track.size();
	SEffectTrack* pTrack = NULL;
	for( size_t i = 0; i < size; ++i )
	{
		pTrack = new SEffectTrack();
		pTrack->fStartPos = Track[i]->fStartPos;
		pTrack->fEndPos = Track[i]->fEndPos;
		
		CEffectUnit* pEffectUnit = NULL;
		if( Track[i]->pEffectUnitProp )
		{
			pEffectUnit = CreateEffectUnit( Track[i]->pEffectUnitProp );
			pEffectUnit->Create( pResMgr );
		}

		pTrack->pEffectUnit = pEffectUnit;

		m_vecEffectUnitTrack.push_back( pTrack );
	}

	return VTRUE;
}

CEffectUnit* CEffect::CreateEffectUnit( IEffectUnitProp* pEffectUnitProp )
{
	int32 nType = pEffectUnitProp->GetType();

	if( nType == EFFECTUNIT_TYPE_TEXTUREANI )
	{
		return new CTextureAnimation( pEffectUnitProp );
	}
	else if( nType == EFFECTUNIT_TYPE_PARTICLESYS )
	{
		return new CParticleSystem( pEffectUnitProp );
	}

	return NULL;
}

void CEffect::ReleaseEffectUnit( IEffectUnit* pEffectUnit )
{
	if( !pEffectUnit )
		return;

	CEffectUnit* pEffectUnitRef = static_cast<CEffectUnit*>(pEffectUnit);
	int32 nType = pEffectUnitRef->GetType();
	
	if( nType == EFFECTUNIT_TYPE_TEXTUREANI )
	{
		CTextureAnimation* pTextureAnim = static_cast<CTextureAnimation*>(pEffectUnit);
		SAFE_DELETE( pTextureAnim );
	}
	else if( nType == EFFECTUNIT_TYPE_PARTICLESYS )
	{
		CParticleSystem* pParticleSystem = static_cast<CParticleSystem*>(pEffectUnit);
		SAFE_DELETE( pParticleSystem );
	}
}

END_WARE
